package edu.ynu.se.xiecheng.achitectureclass.soildata.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.HttpClientErrorException;

import javax.annotation.PostConstruct;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

/**
 * Fbox Token管理服务
 */
@Service
public class FboxTokenService {

    @Value("${fbox.client_id}")
    private String clientId;

    @Value("${fbox.client_secret}")
    private String clientSecret;

    @Value("${fbox.token_url}")
    private String tokenUrl;

    private String accessToken;
    private Instant expiryTime;

    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    private static final Logger logger = LoggerFactory.getLogger(FboxTokenService.class);

    public FboxTokenService() {
        this.restTemplate = new RestTemplate();
        this.objectMapper = new ObjectMapper();
    }

    @PostConstruct
    public void init() {
        try {
            refreshToken();
        } catch (Exception e) {
            logger.error("初始化Token失败: {}", e.getMessage());
            // 不抛出异常，允许应用继续启动
        }
    }

    /**
     * 获取当前有效的Token，若Token即将过期或已失效，则刷新Token
     *
     * @return 当前有效的access_token
     */
    public synchronized String getAccessToken() {
        if (accessToken == null || Instant.now().isAfter(expiryTime.minusSeconds(60))) {
            refreshToken();
        }
        return accessToken;
    }

    /**
     * 刷新Token
     */
    void refreshToken() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        Map<String, String> params = new HashMap<>();
        params.put("client_id", clientId);
        params.put("client_secret", clientSecret);
        params.put("grant_type", "client_credentials");
        params.put("scope", "fbox");

        headers.add("Accept", "application/json");

        StringBuilder requestBody = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (requestBody.length() > 0) {
                requestBody.append("&");
            }
            requestBody.append(entry.getKey())
                      .append("=")
                      .append(entry.getValue());
        }

        HttpEntity<String> request = new HttpEntity<>(requestBody.toString(), headers);

        try {
            logger.info("Token请求信息:");
            logger.info("URL: {}", tokenUrl);
            logger.info("Headers: {}", headers);
            logger.info("Body: {}", requestBody.toString());
            
            ResponseEntity<String> response = restTemplate.postForEntity(tokenUrl, request, String.class);
            logger.info("响应状态码: {}", response.getStatusCode());
            logger.info("响应头: {}", response.getHeaders());
            logger.info("响应体: {}", response.getBody());
            
            if (response.getStatusCode() == HttpStatus.OK) {
                JsonNode jsonNode = objectMapper.readTree(response.getBody());
                accessToken = jsonNode.get("access_token").asText();
                int expiresIn = jsonNode.get("expires_in").asInt();
                expiryTime = Instant.now().plusSeconds(expiresIn);
                logger.info("Token刷新成功，将在{}秒后过期", expiresIn);
            } else {
                logger.error("获取Token失败，状态码: {}", response.getStatusCode());
                throw new RuntimeException("获取Token失败，状态码: " + response.getStatusCode());
            }
        } catch (Exception e) {
            logger.error("获取Token时发生异常: ", e);
            if (e instanceof HttpClientErrorException) {
                HttpClientErrorException httpError = (HttpClientErrorException) e;
                logger.error("HTTP错误状态码: {}", httpError.getStatusCode());
                logger.error("错误响应体: {}", httpError.getResponseBodyAsString());
            }
            throw new RuntimeException("获取Token失败: " + e.getMessage(), e);
        }
    }
}
